#define PrynGuiInternal
#define PrynGuiImplementation
#include <prynGui.h>
#include <pryn.h>

extern PrynResult prynGuiMenuCreatePopupPlatform (PrynGuiMenu *self);
extern PrynResult prynGuiMenuCreateBarPlatform (PrynGuiMenu *self);
extern void prynGuiMenuDestroyPlatform (PrynGuiMenu *self);

/* These need to be implemented by the platform.
	uintptr_t prynGuiMenuDisplay (PrynGuiMenu *self, int x, int y, PrynGuiControl *parent);
	uintptr_t prynGuiMenuItemData (PrynGuiMenu *self, PrynGuiMenuItem id);
	PrynGuiMenuItem prynGuiMenuAppendItem (PrynGuiMenu *self, PrynString label, uintptr_t data);
*/

#define PrynGuiMenuBody(BODY) PrynBaseBody (menu, { state = menu->pState; BODY })
#define PrynGuiMenuGetProperty(PropName, PropType, PropInitial, PropValue) PrynBaseGetProperty (Gui, GuiMenu, menu, PropName, PropType, PropInitial, { *output = PropValue; })
#define PrynGuiMenuSetProperty(PropName, PropType, PropAssign) PrynBaseSetProperty (Gui, GuiMenu, menu, PropName, PropType, PropAssign)

PrynGuiMenuGetProperty (State, PrynState *, 0, state)

static PrynResult Create (PrynGuiMenu **output, PrynState *state, bool popup)
{
	PrynStartFunctionHasState ();
	PrynGuiMenu *menu;
	
	if (output) *output = 0;
	prynAssert (output && state, NullArgument);
	prynCall (prynAllocateClearedObject (state, &menu));
	
	menu->pState = state;
	
	if (popup)
		prynCall (prynGuiMenuCreatePopupPlatform (menu));
	else
		prynCall (prynGuiMenuCreateBarPlatform (menu));
	if (output) *output = menu;
	
	PrynEndFunctionAfterFailure ({
		prynFree (state, menu);
	});
}

PrynGuiExport (PrynResult, prynGuiMenuCreatePopup, (PrynGuiMenu **output, PrynState *state)) { return Create (output, state, true); }
PrynGuiExport (PrynResult, prynGuiMenuCreateBar, (PrynGuiMenu **output, PrynState *state)) { return Create (output, state, false); }

PrynGuiExport (PrynResult, prynGuiMenuDestroy, (PrynGuiMenu *self))
{
	if (!self || !self->pState) return PrynResultNullArgument;
	if (self->pPlatform) prynGuiMenuDestroyPlatform (self);
	prynFree (self->pState, self);
	return PrynResultSuccess;
}

PrynGuiExport (PrynResult, prynGuiMenuDisplayData, (PrynGuiMenu *menu, int x, int y, PrynGuiControl *parent, PrynGuiMenuData *output))
{
	PrynGuiMenuItem selected;
	PrynResult result = prynGuiMenuDisplay (menu, x, y, parent, &selected);

	if (result < 0) return result;
	return prynGuiMenuItemData (menu, selected, output);
}
